package com.naiterui.ehp.bs.doctor.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.form.DesignFormBO;
import com.naiterui.ehp.bp.bo.im.FollowUpImMsgBO;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishParamBO;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DrFollowUpForm;
import com.naiterui.ehp.bp.domain.DrFollowUpRecord;
import com.naiterui.ehp.bp.domain.DrFollowUpRecordForm;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.biz.ScheduleUtils;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.doctor.dto.DrFollowUpRecordDTO;
import com.naiterui.ehp.bs.doctor.dto.DrFollowUpRecordFormDTO;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.fegin.CmsFeginClient;
import com.naiterui.ehp.bs.doctor.fegin.DesignFormFeignClient;
import com.naiterui.ehp.bs.doctor.fegin.ImFeginClient;
import com.naiterui.ehp.bs.doctor.fegin.PatientFeignClient;
import com.naiterui.ehp.bs.doctor.repository.IDoctorRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrFollowUpFormRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrFollowUpRecordFormRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrFollowUpRecordRepository;
import com.naiterui.ehp.bs.doctor.service.IDrFollowUpRecordService;
import com.naiterui.ehp.bs.doctor.vo.followup.AdAddVisitOptionVO;
import com.naiterui.ehp.bs.doctor.vo.followup.AdCalendarPointVO;
import com.naiterui.ehp.bs.doctor.vo.followup.AdVisitSettingVO;
import com.naiterui.ehp.bs.doctor.vo.followup.AdVisitVO;
import com.naiterui.ehp.bs.doctor.vo.followup.DrFollowUpFormTypeVO;
import com.naiterui.ehp.bs.doctor.vo.followup.DrFollowUpFormVO;
import com.naiterui.ehp.bs.doctor.vo.followup.DrFollowUpRecordFormVO;
import com.naiterui.ehp.bs.doctor.vo.followup.DrFollowUpRecordVO;
import com.naiterui.ehp.bs.doctor.vo.followup.DrFollowUpSubVisitVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yangfuya
 * @since 2022/1/5
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdFollowUpRecordServiceImpl implements IDrFollowUpRecordService {
    private final IDrFollowUpFormRepository followUpFormRepository;
    private final IDrFollowUpRecordRepository followUpRecordRepository;
    private final IDrFollowUpRecordFormRepository followUpRecordFormRepository;
    private final DesignFormFeignClient designFormFeignClient;
    private final CmsFeginClient cmsFeginClient;
    private final ImFeginClient imFeginClient;
    private final PatientFeignClient patientFeignClient;
    private final IDoctorRepository doctorRepository;

    @Override
    public PageVO<DrFollowUpRecordVO> page(Long doctorId, Integer status, String inquirerName, String sort,
                                           PageParamVO pageParamVO) throws BusinessException {
        Page<DrFollowUpRecord> page;
        Sort endTime;
        if (StrUtil.isNotBlank(sort) && "asc".equals(sort)) {
            endTime = Sort.by(Sort.Order.asc("endTime"));
        } else {
            endTime = Sort.by(Sort.Order.desc("endTime"));
        }
        if (StrUtil.isBlank(inquirerName)) {
            page = this.followUpRecordRepository.findByDoctorIdAndStatus(doctorId, status,
                    pageParamVO.getPageable(endTime));
        } else {
            page = this.followUpRecordRepository.findByDoctorIdAndStatusAndInquirerNameLike(doctorId, status,
                    "%" + inquirerName + "%", pageParamVO.getPageable(endTime));
        }
        List<DrFollowUpRecord> content = page.getContent();
        if (CollUtil.isEmpty(content)) {
            return PageVO.newBuilder().pageNo(page.getNumber()).pageSize(page.getSize())
                    .totalCount((int) page.getTotalElements()).result(Collections.EMPTY_LIST).build();
        }
        Set<Long> followUpIdSet = content.stream().map(DrFollowUpRecord::getId).collect(Collectors.toSet());
        List<DrFollowUpRecordForm> recordForms =
                this.followUpRecordFormRepository.findAllByAndFollowUpIdIn(followUpIdSet);
        Map<Long,
                List<DrFollowUpRecordFormVO>> upRecordFormMap = recordForms.stream()
                .map(r -> DrFollowUpRecordFormVO.builder().followUpId(r.getFollowUpId())
                        .followUpFormId(r.getFollowUpFormId()).followUpRecordFormId(r.getId()).formName(r.getFormName())
                        .fillingStatus(r.getFillingStatus()).build())
                .collect(Collectors.groupingBy(DrFollowUpRecordFormVO::getFollowUpId, Collectors.toList()));
        return PageVO.newBuilder().pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
                .totalCount((int) page.getTotalElements())
                .result(content.stream()
                        .map(r -> DrFollowUpRecordVO.builder().id(r.getId()).name(r.getName()).doctorId(r.getDoctorId())
                                .patientId(r.getPatientId()).inquirerId(r.getInquirerId()).inquirerName(r.getInquirerName())
                                .inquirerGender(r.getInquirerGender()).inquirerAge(r.getInquirerAge()).beginTime(r.getBeginTime())
                                .status(r.getStatus()).createdAt(r.getCreatedAt())
                                .followUpFormList(upRecordFormMap.get(r.getId())).build())
                        .collect(Collectors.toList()))
                .build();
    }

    @Override
    public List<DrFollowUpFormTypeVO> getFollowUpFormTypeList() throws BusinessException {
        return cmsFeginClient.vueList("follow_up_form_type");
    }

    @Override
    public PageVO<DrFollowUpFormVO> followUpFormPage(Long doctorId, Integer type, String formName, PageParamVO pageParamVO)
            throws BusinessException {
        Page<DrFollowUpForm> page = null;
        if (0 == type && StrUtil.isNotBlank(formName)) {
            page = this.followUpFormRepository.findByNameLikeAndDelFlagAndStatus("%" + formName + "%", 0, 0, pageParamVO.getPageable());
        } else {
            page = this.followUpFormRepository.findByTypeAndDelFlagAndStatus(type, 0, 0, pageParamVO.getPageable());
        }
        List<DrFollowUpForm> content = page.getContent();
        if (CollUtil.isEmpty(content)) {
            return PageVO.newBuilder().pageNo(page.getNumber()).pageSize(page.getSize())
                    .totalCount((int) page.getTotalElements()).result(Collections.EMPTY_LIST).build();
        }
        return PageVO.newBuilder().pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
                .totalCount((int) page.getTotalElements())
                .result(content.stream()
                        .map(ff -> DrFollowUpFormVO.builder().followUpFormId(ff.getId()).formName(ff.getName()).build())
                        .collect(Collectors.toList()))
                .build();
    }

    @Override
    public DrFollowUpRecordVO getById(Long id) throws BusinessException {
        DrFollowUpRecord followUpRecord = this.followUpRecordRepository.findFirstById(id);
        if (followUpRecord == null) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_NOT_EXIST);
        }
        DrFollowUpRecordVO followUpRecordVO = DrFollowUpRecordVO.builder().build();
        BeanUtil.copyProperties(followUpRecord, followUpRecordVO);
        Doctor doctor = this.doctorRepository.get(followUpRecord.getDoctorId());
        followUpRecordVO.setDoctorName(doctor == null ? "" : doctor.getName());
        followUpRecordVO.setVisitRecordType(followUpRecord.getOnlineType());
        //计划类型
        Boolean isAqVisit = DrFollowUpRecord.TYPE_QA == followUpRecord.getType();
        //是否可以报道或者填写问卷
        Boolean canConsult = false;
        Date now = new Date();
        Date beginTime = DateUtil.parseStrToDateTime(DateUtil.parseDateToString(followUpRecordVO.getBeginTime(), DateUtil.DATE_FORMAT) + " 10:00:00");
        if (isAqVisit) {
            List<DrFollowUpRecordForm> upRecordFormList =
                    this.followUpRecordFormRepository.findAllByAndFollowUpId(followUpRecord.getId());
            List<DrFollowUpRecordFormVO> upRecordFormVOList = new ArrayList<>();
            if (CollUtil.isNotEmpty(upRecordFormList)) {
                // 第一个表单带入内容
                DrFollowUpRecordForm drFollowUpRecordForm = upRecordFormList.stream().findFirst().get();
                DesignFormBO designForm = designFormFeignClient.getDesignFormDataVO(drFollowUpRecordForm.getFormId(),
                        drFollowUpRecordForm.getId().toString());
                upRecordFormVOList = upRecordFormList.stream()
                        .map(up -> DrFollowUpRecordFormVO.builder().followUpRecordFormId(up.getId())
                                .followUpFormId(up.getFollowUpFormId()).formName(up.getFormName())
                                .fillingStatus(up.getFillingStatus()).build())
                        .collect(Collectors.toList());
                if (designForm != null) {
                    upRecordFormVOList.stream().findFirst().get().setDesignForm(designForm);
                }
            }
            followUpRecordVO.setFollowUpFormList(upRecordFormVOList);
            if (followUpRecordVO.getStatus() == DrFollowUpRecord.STARTED && now.after(beginTime)) {
                canConsult = true;
            }
        } else {
            followUpRecordVO.setVisitRecord(StrUtil.blankToDefault(followUpRecordVO.getVisitRecord(), ""));
            //复诊
            if (followUpRecordVO.getStatus() == DrFollowUpRecord.NOT_STARTED && now.after(beginTime)) {
                canConsult = true;
            }
        }
        followUpRecordVO.setCanConsult(canConsult);
        return followUpRecordVO;
    }

    @Override
    public DrFollowUpRecordFormVO switchForm(Long followUpRecordFormId) throws BusinessException {
        DrFollowUpRecordForm followUpRecordForm = this.followUpRecordFormRepository.findFirstById(followUpRecordFormId);
        if (followUpRecordForm == null) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_NOT_EXIST);
        }
        DesignFormBO designForm =
                designFormFeignClient.getDesignFormDataVO(followUpRecordForm.getFormId(), followUpRecordFormId.toString());
        return DrFollowUpRecordFormVO.builder().followUpRecordFormId(followUpRecordFormId)
                .followUpFormId(followUpRecordForm.getFollowUpFormId()).formName(followUpRecordForm.getFormName())
                .fillingStatus(followUpRecordForm.getFillingStatus()).designForm(designForm).build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(DrFollowUpRecordDTO drFollowUpRecordDTO) throws BusinessException {
        //验证参数
        List<String> dateList = validateParam(drFollowUpRecordDTO);
        List<Date> collectDate = dateList.stream().map(s -> DateUtil.parseStrToCustomPatternDate(s + " 00:00:00", DateUtil.DATE_TIME_FORMAT)).collect(Collectors.toList());
        List<DrFollowUpRecord> patientVisitList = this.followUpRecordRepository.findByDoctorIdAndPatientIdAndTypeAndStatusNotAndBeginTimeIn(drFollowUpRecordDTO.getDoctorId(), drFollowUpRecordDTO.getPatientId(), drFollowUpRecordDTO.getType(), DrFollowUpRecord.CANCEL, collectDate);
        if (CollectionUtils.isNotEmpty(patientVisitList)) {
            Date date = patientVisitList.get(0).getBeginTime();
            String msg = String.format("该患者已有%s随访计划，请修改后再试", DateUtil.formatDate(date, DateUtil.DATE_FORMAT));
            throw new BusinessException(ExceptionCodes.DATA_ERR, msg);
        }
        //判断随访类型
        Boolean isAqVisit = DrFollowUpRecord.TYPE_QA == drFollowUpRecordDTO.getType();
        String visitRecordNo = getVisitRecordNo(drFollowUpRecordDTO.getType());
        List<DrFollowUpRecord> records = new ArrayList<>();
        collectDate = collectDate.stream().sorted().collect(Collectors.toList());
        //保存随访计划
        for (int i = 0; i < collectDate.size(); i++) {
            Date beginDate = collectDate.get(i);
            DrFollowUpRecord drFollowUpRecord = new DrFollowUpRecord();
            BeanUtil.copyProperties(drFollowUpRecordDTO, drFollowUpRecord);
            if (!isAqVisit) {
                drFollowUpRecord.setName("第" + numberChineseFormatter(i + 1) + "次随访");
            }
            drFollowUpRecord.setStatus(DrFollowUpRecord.NOT_STARTED);
            drFollowUpRecord.setBeginTime(beginDate);
            drFollowUpRecord.setEndTime(DateUtil.addDays(beginDate, 1));
            drFollowUpRecord.setFollowNo(visitRecordNo);
            drFollowUpRecord.setCompleteStatus(0);
            drFollowUpRecord.setOnlineType(0);
            drFollowUpRecord.setConsultType(0);
            drFollowUpRecord.setCreatedAt(new Date());
            drFollowUpRecord.setChangedAt(new Date());
            records.add(drFollowUpRecord);
        }
        Iterable<DrFollowUpRecord> saveResult = this.followUpRecordRepository.saveAll(records);
        DrFollowUpRecord drFollowUpRecord = saveResult.iterator().next();
        if (isAqVisit) {
            //随访问卷处理
            List<DrFollowUpRecordFormDTO> followUpRecordFormList = drFollowUpRecordDTO.getFollowUpFormList();
            Set<Long> followUpFormIdSet =
                    followUpRecordFormList.stream().map(DrFollowUpRecordFormDTO::getFollowUpFormId).collect(Collectors.toSet());
            List<DrFollowUpForm> drFollowUpFormList = this.followUpFormRepository.findAllByIdIn(followUpFormIdSet);

            List<DrFollowUpRecordForm> drFollowUpRecordForms = new ArrayList<>();
            DrFollowUpRecordForm followUpRecordForm = null;
            Long followUpRecordId = drFollowUpRecord.getId();
            for (DrFollowUpForm drFollowUpForm : drFollowUpFormList) {
                if (drFollowUpForm.getDelFlag() != 0) {
                    throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_FORM_IS_NULL);
                }
                if (drFollowUpForm.getStatus() != 0) {
                    throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_FORM_IS_CLOSE);
                }
                String formId = this.designFormFeignClient.copyDesignForm(drFollowUpForm.getFormId());
                followUpRecordForm = new DrFollowUpRecordForm();
                followUpRecordForm.setFollowUpId(followUpRecordId);
                followUpRecordForm.setFollowUpFormId(drFollowUpForm.getId());
                followUpRecordForm.setFormId(formId);
                followUpRecordForm.setFormName(drFollowUpForm.getName());
                followUpRecordForm.setFillingStatus(DrFollowUpRecordForm.NOT_FILLIN);
                followUpRecordForm.setCreatedAt(new Date());
                drFollowUpRecordForms.add(followUpRecordForm);
            }
            this.followUpRecordFormRepository.saveAll(drFollowUpRecordForms);
        }
        //发送im卡片
        imFeginClient.sendFollowUp(FollowUpImMsgBO.builder().doctorId(drFollowUpRecordDTO.getDoctorId())
                .patientId(drFollowUpRecordDTO.getPatientId()).inquirerId(drFollowUpRecordDTO.getInquirerId())
                .followUpId(drFollowUpRecord.getId()).followUpName(drFollowUpRecord.getName())
                .followUpNo(visitRecordNo).type(drFollowUpRecordDTO.getType())
                .beginTime(DateUtil.parseDateToString(collectDate.get(0), DateUtil.DATE_FORMAT))
                .followUpRemind("为你制定了" + (isAqVisit ? "随访问卷" : "复诊计划") + "，请按时处理").build());
    }

    private List<String> validateParam(DrFollowUpRecordDTO drFollowUpRecordDTO) throws BusinessException {
        List<String> dateList = Splitter.on(",").trimResults().splitToList(drFollowUpRecordDTO.getDates());
        int originalDateSize = dateList.size();
        if (CollectionUtils.isEmpty(dateList) || originalDateSize > 4) {
            log.warn("添加随访请求参数异常：drFollowUpRecordDTO={}", drFollowUpRecordDTO);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        List<String> distinctList = dateList.stream().distinct().collect(Collectors.toList());
        if (originalDateSize != distinctList.size()) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR, "请勿选择重复日期");
        }
        Boolean errorDate = dateList.stream().anyMatch(d -> DateUtil.compareDate(DateUtil.parseStrToDate(d), new Date()) < 0);
        if (errorDate) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_BEGIN_TIME_LT_NOW);
        }
        return dateList;
    }


    public String numberChineseFormatter(int number) {
        return NumberChineseFormatter.format(Double.valueOf(number), false, false);
    }

    @Override
    public void delete(Long id) throws BusinessException {
        DrFollowUpRecord drFollowUpRecord = this.followUpRecordRepository.findFirstById(id);
        if (drFollowUpRecord == null) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_NOT_EXIST);
        }
        if (drFollowUpRecord.getStatus() != 0) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_BEGIN);
        }
        this.followUpRecordRepository.deleteById(id);
        ScheduleUtils.removeCustomerTask(ConfigUtil.getString("schedule.host.url"), ScheduleUtils.TASH_TYPE_FOLLOW_UP,
                drFollowUpRecord.getId().toString());
    }

    @Override
    public DesignFormBO viewForm(Long followUpFormId) throws BusinessException {
        DrFollowUpForm followUpForm = this.followUpFormRepository.get(followUpFormId);
        if (followUpForm == null) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_FORM_IS_NULL);
        }
        return this.designFormFeignClient.getDesignForm(followUpForm.getFormId());
    }

    /**
     * 获取包含多个复诊计划的详情
     *
     * @param followNo
     * @return
     */
    @Override
    public List<DrFollowUpSubVisitVO> getSubsequentVisitByFollowNo(String followNo) throws BusinessException {
        List<DrFollowUpSubVisitVO> result = new ArrayList<>();
        List<DrFollowUpRecord> records = this.followUpRecordRepository.findAllByFollowNo(followNo);
        if (CollUtil.isNotEmpty(records)) {
            result = records.stream().map(r -> {
                DrFollowUpSubVisitVO vo = new DrFollowUpSubVisitVO();
                BeanUtil.copyProperties(r, vo);
                return vo;
            }).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 医生主动设置复诊计划为已报道或已取消
     *
     * @param settingVO
     * @throws BusinessException
     */
    @Override
    public void updateVisitRecordStatus(AdVisitSettingVO settingVO) throws BusinessException {
        DrFollowUpRecord drFollowUpRecord = this.followUpRecordRepository.findFirstById(settingVO.getId());
        if (drFollowUpRecord == null) {
            throw new BusinessException(BaseExceptionCodes.FOLLOW_UP_RECORD_NOT_EXIST);
        }
        if (AdVisitSettingVO.REPORT == settingVO.getVisitStatus() && DrFollowUpRecord.TYPE_SUBSEQUENT == drFollowUpRecord.getType()) {
            drFollowUpRecord.setStatus(DrFollowUpRecord.STARTED);
            drFollowUpRecord.setVisitRecord(settingVO.getSuggestion());
            drFollowUpRecord.setChangedAt(new Date());
            drFollowUpRecord.setCompleteStatus(DrFollowUpRecord.COM_STATUS_YES);
            drFollowUpRecord.setCompleteTime(new Date());
            drFollowUpRecord.setOnlineType(DrFollowUpRecord.ONLINE_TYPE_DOWN);
            followUpRecordRepository.update(drFollowUpRecord);
        } else if (AdVisitSettingVO.CANCEL == settingVO.getVisitStatus()) {
            drFollowUpRecord.setStatus(DrFollowUpRecord.CANCEL);
            drFollowUpRecord.setReason(settingVO.getSuggestion());
            drFollowUpRecord.setChangedAt(new Date());
            followUpRecordRepository.update(drFollowUpRecord);
            //发送取消的订阅消息
            patientFeignClient.publishMaMessage(MsgMaPublishParamBO.builder().doctorId(drFollowUpRecord.getDoctorId())
                    .patientId(drFollowUpRecord.getPatientId()).msgType(MsgMaPublishParamBO.MsgType.FOLLOW_UP_CANCEL)
                    .followUpId(drFollowUpRecord.getId()).content("取消原因：" + settingVO.getSuggestion()).build());
        }

    }

    @Override
    public PageVO<AdVisitVO> getVisitTodayPage(Long doctorId, String date, PageParamVO pageParamVO) throws BusinessException {
        Date beginDate = DateUtil.parseStrToDateTime(date + " 00:00:00");
        Page<DrFollowUpRecord> page = this.followUpRecordRepository.findByDoctorIdAndBeginTime(doctorId, beginDate, pageParamVO.getPageable());
        List<DrFollowUpRecord> content = page.getContent();
        if (CollUtil.isEmpty(content)) {
            return PageVO.newBuilder().pageNo(page.getNumber()).pageSize(page.getSize())
                    .totalCount((int) page.getTotalElements()).result(Collections.EMPTY_LIST).build();
        }
        List<AdVisitVO> visitListPageVo = this.getVisitListVO(content);
        return PageVO.newBuilder().pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
                .totalCount((int) page.getTotalElements())
                .result(visitListPageVo)
                .build();
    }

    private List<AdVisitVO> getVisitListVO(List<DrFollowUpRecord> content) {
        Date now = new Date();
        List<AdVisitVO> result = content.stream().map(c -> {
            AdVisitVO vo = new AdVisitVO();
            BeanUtil.copyProperties(c, vo);
            vo.setComplete(DrFollowUpRecord.CANCEL != c.getStatus() && now.after(c.getEndTime()) && DrFollowUpRecord.COM_STATUS_NO == c.getCompleteStatus());
            return vo;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public List<AdCalendarPointVO> getMonthVisit(Long doctorId, String month) throws BusinessException {

        List<AdCalendarPointVO> pointVOS = new ArrayList<>();
        DateTime beginTime = cn.hutool.core.date.DateUtil.beginOfMonth(DateUtil.parseStrToDate(month + "-01"));
        DateTime endTime = cn.hutool.core.date.DateUtil.endOfMonth(DateUtil.parseStrToDate(month + "-01"));
        List<DrFollowUpRecord> result = this.followUpRecordRepository.findByDoctorIdAndBeginTimeBetween(doctorId, beginTime.toJdkDate(), endTime.toJdkDate());
        if (CollUtil.isNotEmpty(result)) {
            Map<String, List<DrFollowUpRecord>> beginTimeMap = result.stream().collect(Collectors.groupingBy(r -> DateUtil.formatDate(r.getBeginTime(), DateUtil.DATE_FORMAT)));
            beginTimeMap.forEach((k, v) -> {
                AdCalendarPointVO vo = new AdCalendarPointVO();
                vo.setDay(k);
                vo.setStatus(handleCalendarStatus(v));
                pointVOS.add(vo);
            });
        }
        return pointVOS;
    }

    private Integer handleCalendarStatus(List<DrFollowUpRecord> result) {
        Date now = new Date();
        Boolean expire = result.get(0).getEndTime().before(now);
        Boolean allCancel = result.stream().allMatch(r -> DrFollowUpRecord.CANCEL == r.getStatus());
        Boolean anyNotComplete = !allCancel && result.stream().anyMatch(r -> DrFollowUpRecord.COM_STATUS_NO == r.getCompleteStatus() && DrFollowUpRecord.CANCEL != r.getStatus());
        if (expire && anyNotComplete) {
            return AdCalendarPointVO.RED;
        } else if (!expire && anyNotComplete) {
            return AdCalendarPointVO.ORANGE;
        } else {
            return AdCalendarPointVO.GRAY;
        }
    }

    @Override
    public List<Map<String, Object>> getOption() {
        List<Map<String, Object>> list = Lists.newArrayList();
        Map<String, Object> oneMap = Maps.newLinkedHashMap();
        List<AdAddVisitOptionVO> one = Lists.newArrayList();
        one.add(new AdAddVisitOptionVO("三天后", 3));
        one.add(new AdAddVisitOptionVO("一周后", 7));
        one.add(new AdAddVisitOptionVO("两周后", 14));
        one.add(new AdAddVisitOptionVO("一月后", 30));
        oneMap.put("key", "第一次随访");
        oneMap.put("value", one);
        list.add(oneMap);

        Map<String, Object> twoMap = Maps.newLinkedHashMap();
        List<AdAddVisitOptionVO> two = Lists.newArrayList();
        two.add(new AdAddVisitOptionVO("两周后", 14));
        two.add(new AdAddVisitOptionVO("一月后", 30));
        two.add(new AdAddVisitOptionVO("两月后", 60));
        two.add(new AdAddVisitOptionVO("三月后", 90));
        twoMap.put("key", "第二次随访");
        twoMap.put("value", two);
        list.add(twoMap);

        Map<String, Object> threeMap = Maps.newLinkedHashMap();
        List<AdAddVisitOptionVO> three = Lists.newArrayList();
        three.add(new AdAddVisitOptionVO("两月后", 60));
        three.add(new AdAddVisitOptionVO("三月后", 90));
        three.add(new AdAddVisitOptionVO("四月后", 120));
        three.add(new AdAddVisitOptionVO("五月后", 150));
        threeMap.put("key", "第三次随访");
        threeMap.put("value", three);
        list.add(threeMap);

        Map<String, Object> fourMap = Maps.newLinkedHashMap();
        List<AdAddVisitOptionVO> four = Lists.newArrayList();
        four.add(new AdAddVisitOptionVO("三月后", 90));
        four.add(new AdAddVisitOptionVO("六月后", 180));
        four.add(new AdAddVisitOptionVO("九月后", 270));
        four.add(new AdAddVisitOptionVO("一年", 360));
        fourMap.put("key", "第四次随访");
        fourMap.put("value", four);
        list.add(fourMap);

        return list;
    }

    @Override
    public DesignFormBO getDesignFormDataBO(String formId, String businessId) throws BusinessException {
        log.info("formId={}, businessId={}", formId, businessId);
        return designFormFeignClient.getDesignFormDataVO(formId, businessId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateVisitCompleteStatus(Long doctorId, Long patientId, Date consultTime, Integer consultType, String roomId, Long videoConsultId) throws BusinessException {
        log.info("图文视频问诊处理随访任务：doctorId={}，patientId={}，consultTime={}，consultType={}，roomId={}，videoConsultId={}",
                doctorId, patientId, consultTime, consultType, roomId, videoConsultId);
        Date date = cn.hutool.core.date.DateUtil.beginOfDay(consultTime).toJdkDate();
        List<DrFollowUpRecord> result = this.followUpRecordRepository.findByDoctorIdAndPatientIdAndBeginTimeAndType(doctorId, patientId, date, DrFollowUpRecord.TYPE_SUBSEQUENT);
        if (CollUtil.isNotEmpty(result)) {
            result.forEach(d -> {
                if (d.getStatus() != DrFollowUpRecord.STARTED) {
                    d.setStatus(DrFollowUpRecord.STARTED);
                    d.setChangedAt(new Date());
                    d.setCompleteStatus(DrFollowUpRecord.COM_STATUS_YES);
                    d.setCompleteTime(new Date());
                    d.setOnlineType(DrFollowUpRecord.ONLINE_TYPE_UP);
                    d.setRoomId(roomId);
                    d.setVideoConsultId(videoConsultId);
                    d.setConsultType(consultType);
                    followUpRecordRepository.update(d);
                }
            });
        }
    }

    /**
     * 随访号生成
     *
     * @param visitRecordType
     * @return
     */
    private String getVisitRecordNo(int visitRecordType) {
        String snowflakeNo = String.valueOf(IdUtil.getSnowflake(1, 1).nextId());
        String no = visitRecordType + DateUtil.formatDate(new Date(), "yyMMddHHmmss") + snowflakeNo.substring(snowflakeNo.length() - 6);
        return no;
    }
}
